/* $Id: TeamStats.java 39 2009-07-24 22:48:06Z h_m_r@gmx.de $ */
package org.jugger.tournament.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;

/**
 * @author Sven Hamer
 */
public class TeamStats {

    private Stats stats;
    private Stats opponentsStats;
    private ArrayList<Match> matches;

	private final Team team;
	public Team getTeam() {
		return team;
	}
	public Collection<Team> getOpponents() {
		HashSet<Team> opponents = new HashSet<Team>();
		for(Match match: matches) {
			opponents.add(match.getOpponent(team));
		}
		return opponents;
	}
	public Collection<Match> getMatches() {
		return matches;
	}
	public Stats getStats() {
		return stats;
	}
	public Stats getOpponentsStats() {
		return opponentsStats;
	}

	/**
	 * Constructs an empty stats set for given team.
	 * All values are init with 0 and opponents list ist empty.
	 * @param team
	 */
	public TeamStats(Team team) {
		this.team = team;
        this.stats = new Stats();
        this.opponentsStats = new Stats();
        this.matches = new ArrayList<Match>();
	}

	/**
	 * Copy constructor
	 * @param teamStats
	 */
	public TeamStats(TeamStats teamStats) {
		team = teamStats.getTeam();
		stats = teamStats.getStats();
		opponentsStats = teamStats.getOpponentsStats();
		matches = new ArrayList<Match>(teamStats.getMatches());
	}

    /**
     * Adds given stats to current opponenents stats.
     * @param diffStats
     */
	private void updateOpponentsStats(Stats diffStats) {
		opponentsStats = new Stats(opponentsStats, diffStats);
    }

    /**
     * Updates this team stats with given match.
     * Side effect: Invokes updateOpponentsStats for current teamStats of all opponents of this team.
     * Only for intern use; invoked by updateStats.
     * @param match
     */
	public void updateStats(Match match) {
    	if(match.containsTeam(team) && match.isFinished()) {

			// calculate diffStats
			Stats diffStats = null;
			int pointsPositive = match.getPointsForTeam(team);
			int pointsNegative = match.getPointsForOpponent(team);
			int scorePositive = match.getScoreForTeam(team);
			int scoreNegative = match.getScoreForOpponent(team);

			if(match.isDrawn()) {
				diffStats = new Stats(0, 1, 0, pointsPositive, pointsNegative, scorePositive, scoreNegative);
			}
			else if(match.getWinner() == team) {
				diffStats = new Stats(1, 0, 0, pointsPositive, pointsNegative, scorePositive, scoreNegative);
			}
			else {
				diffStats = new Stats(0, 0, 1, pointsPositive, pointsNegative, scorePositive, scoreNegative);
			}

			// update stats with diffStats
			stats = new Stats(stats, diffStats);

			// update "opponent stats" on all opponents.
			for(Team opponent: getOpponents()) {
				opponent.getCurrentTeamStats().updateOpponentsStats(diffStats);
			}

			// if not played against current opponent yet => add own stats to its opponentstats.
			if(!getOpponents().contains(match.getOpponent(team))) {
				match.getOpponent(team).getCurrentTeamStats().updateOpponentsStats(stats);
			}

			// add match to list
			matches.add(match);
    	}
    }


    /**
     * Reverts this team stats with given match. (all changes of that match will be reverted)
     * Side effect: Invokes updateOpponentsStats for current teamStats of all opponents of this team.
     * Only for intern use; invoked by updateStats.
     * @param match
     */
	public void revertStats(Match match) {
    	if(match.containsTeam(team) && matches.contains(match)) {

			// calculate diffStats
			Stats diffStats = null;
			int pointsPositive = -match.getPointsForTeam(team);
			int pointsNegative = -match.getPointsForOpponent(team);
			int scorePositive = -match.getScoreForTeam(team);
			int scoreNegative = -match.getScoreForOpponent(team);

			if(match.isDrawn()) {
				diffStats = new Stats(0, -1, 0, pointsPositive, pointsNegative, scorePositive, scoreNegative);
			}
			else if(match.getWinner() == team) {
				diffStats = new Stats(-1, 0, 0, pointsPositive, pointsNegative, scorePositive, scoreNegative);
			}
			else {
				diffStats = new Stats(0, 0, -1, pointsPositive, pointsNegative, scorePositive, scoreNegative);
			}

			// remove match from list
			matches.remove(match);

			// update "opponent stats" on all opponents.
			for(Team opponent: getOpponents()) {
				opponent.getCurrentTeamStats().updateOpponentsStats(diffStats);
			}

			// if not played against current opponent in another match => remove own stats from its opponentstats.
			if(!getOpponents().contains(match.getOpponent(team))) {
				match.getOpponent(team).getCurrentTeamStats().updateOpponentsStats(stats.negate());
			}

			// update stats with diffStats
			stats = new Stats(stats, diffStats);
    	}
    }


	/**
	 * Updates the team stats for two teams based on a given match match.
	 * @param match
	 */
	public static void updateTeamStats(Match match) {
		match.getTeamA().getCurrentTeamStats().updateStats(match);
		match.getTeamB().getCurrentTeamStats().updateStats(match);
	}

	/**
	 * Reverts all changes, that given match has done.
	 * @param match
	 */
	public static void revertTeamStats(Match match) {
		match.getTeamA().getCurrentTeamStats().revertStats(match);
		match.getTeamB().getCurrentTeamStats().revertStats(match);
	}

	@Override
	public String toString() {
		return team+" ("+stats+") | "+getOpponentsStats()+")";
	}
}
